package com.cube.share.base.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author litb
 * @since 2022/12/28 13:50
 * <p>
 * 转义工具
 */
public class EscapeUtil {

    public static String escapeSql(String x) {
        int stringLength = x.length();
        String parameterAsString = x;

        if (isEscapeNeededForString(x, stringLength)) {

            StringBuffer buf = new StringBuffer((int) (x.length() * 1.1));

            // buf.append('\'');

            //
            // Note: buf.append(char) is _faster_ than
            // appending in blocks, because the block
            // append requires a System.arraycopy()....
            // go figure...
            //

            for (int i = 0; i < stringLength; ++i) {
                char c = x.charAt(i);

                switch (c) {
                    case 0: /* Must be escaped for 'mysql' */
                        buf.append('\\');
                        buf.append('0');

                        break;

                    case '\n': /* Must be escaped for logs */
                        buf.append('\\');
                        buf.append('n');

                        break;

                    case '\r':
                        buf.append('\\');
                        buf.append('r');

                        break;

                    case '\\':
                        buf.append('\\');
                        buf.append('\\');

                        break;

                    case '\'':
                        buf.append('\\');
                        buf.append('\'');

                        break;

                    case '"': /* Better safe than sorry */
                        if (true) {
                            buf.append('\\');
                        }

                        buf.append('"');

                        break;

                    case '\032': /* This gives problems on Win32 */
                        buf.append('\\');
                        buf.append('Z');

                        break;

                    default:
                        buf.append(c);
                }
            }

            // buf.append('\'');
            parameterAsString = buf.toString();

        }
        return parameterAsString;
    }

    private static boolean isEscapeNeededForString(String x, int stringLength) {
        boolean needsHexEscape = false;

        for (int i = 0; i < stringLength; ++i) {
            char c = x.charAt(i);

            switch (c) {
                case 0: /* Must be escaped for 'mysql' */

                    needsHexEscape = true;
                    break;

                case '\n': /* Must be escaped for logs */
                    needsHexEscape = true;

                    break;

                case '\r':
                    needsHexEscape = true;
                    break;

                case '\\':
                    needsHexEscape = true;

                    break;

                case '\'':
                    needsHexEscape = true;

                    break;

                case '"': /* Better safe than sorry */
                    needsHexEscape = true;

                    break;

                case '\032': /* This gives problems on Win32 */
                    needsHexEscape = true;
                    break;
            }

            if (needsHexEscape) {
                break; // no need to scan more
            }
        }
        return needsHexEscape;
    }

    /**
     * 包括左右尖括号替换
     *
     * @param obj
     * @return
     */
    public static Object escapeHtml(Object obj) {
        if (obj instanceof String) {
            String str = (String) obj;
            StringBuilder writer = new StringBuilder((int) (str.length() * 1.5));
            //EntitiesDev.HTML40.escape(writer, str);
            return writer.toString();
        }
        return obj;
    }

    /**
     * 包括左右尖括号、双引号替换
     *
     * @param obj
     * @return
     */
    public static Object escapeHtmlMore(Object obj) {
        if (obj instanceof String) {
            String str = (String) obj;
            StringBuilder writer = new StringBuilder((int) (str.length() * 1.5));
            //EntitiesDev.HTML40.escape(writer, str);
            return writer.toString();
        }
        return obj;
    }

    /**
     * ibatis查询参数SQL注入保护
     * <p>
     * 参数支持类型：{@code String、Map<String, Object>} <br>
     *
     * @param obj
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Object protectSql(Object obj) {
        if (obj instanceof String) {
            return escapeSql((String) obj);
        } else if (obj instanceof Map) {
            Map<String, Object> hull = new HashMap<String, Object>();
            Map<String, Object> map = (Map<String, Object>) obj;
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value != null) {
                    if (value instanceof String) {
                        value = escapeSql((String) value);
                    }
                }
                hull.put(key, value);
            }
            return hull;
        }
        return obj;
    }
}
